package zbl.c0.symbol;

import java.util.ArrayList;
import java.util.Hashtable;

/**
 * 		函数表，存储每一个函数的所有相关信息，以及
 * 函数内部的符号表。
 * @author 朱伯龙
 *  
 */
public class FuncTable {

	public String funcname;							//  函数名称
	
	public Hashtable<String, Symbol> symtable;		//  内部符号表
	
	public ArrayList<Symbol> argTable = null;		//  参数表
	
	public final int retType;						//  返回类型
	
	public boolean hasArgs;							//  是否有参数
	
	public int hasRet;								//  是否有返回语句
						//  0表示没有 , 1表示只有return , 2表示return <exp>
	
	public static int VOID = 0;						//  定义返回类型标记
	public static int INT = 1;
	
	private static int MAX_ARGS = 10;				//  最大参数数目
	
	public int addr;								//  函数的入口地址
	
	private static int offset;						//  相对地址，参数或者内部符号相对于函数的偏移地址
	
	public FuncTable(String funcname, int retType){
		this.funcname = funcname;
		this.retType = retType;
		symtable = new Hashtable<String, Symbol>();	//  为函数内符号表分配存储空间
		argTable = new ArrayList<Symbol>();
		hasRet = 0;									//  初始化为没有返回语句
		offset = 3;		
						//	预留0保存   SL  静态链			保存直接外层基地址   这里一律为  0 （全局变量的基地址）
						//	预留1保存   DL  动态链			保存调用该函数的数据栈的基地址
						//	预留2保存   RA  返回地址		保存代码栈的返回地址
	}
	
	
	/**
	 * 		在函数参数表中查找指定名称的参数
	 * @param arg
	 * @return
	 */
	public Symbol getArgs(String arg){				//  根据所给的形参名，取得形参信息
													//  如果没有则返回null
		Symbol curSym;
		for(int i=0; i<argTable.size(); i++)
		{
			curSym = argTable.get(i);
			if(arg.equals(curSym.name))
				return curSym;
		}
		return null;
	}
	/**
	 * 		向函数参数表中添加一个参数
	 * @param arg
	 * @param address
	 */
	public boolean addArgs(String arg){							//  添加参数信息
		if(argTable.size() > MAX_ARGS)
		{
			System.out.println("函数参数数目超过限制，无法添加");
			return false;
		}
		
		if(getArgs(arg)==null)					//  如果当前参数表中没有该参数, 则添加
		{										//  参数是变量，则value表示变量的地址，调用变量符号的构造方法
			Symbol curSymbol = new Symbol(arg, offset++, 0);
			argTable.add(curSymbol);
			return true;
		}
		else{												//  参数名已经存在，重复报错！！！
			System.out.println("函数  "+funcname+" 参数   "+ arg +"  已经定义");
			return false;
		}
	}
	/**
	 * 			向函数符号表中添加一个符号
	 * @param name
	 * @param type
	 * @param value		根据类型来决定value到底是常量的值还是变量的相对地址
	 * @return
	 */
	public boolean reserve(String name, int type, int value) 
	{ 	
		if(getSym(name)!=null)								//符号已经存在，重复报错！！！
		{
			System.out.println("函数  "+funcname+"  内符号   "+name+"  已经定义");
			return false;
		}
		else if(getArgs(name)!=null){
			System.out.println("函数  "+funcname+"  内符号   "+name+"  已经定义为参数");
			return false;
		}else{												//如果当前符号表中没有该符号, 则添加
			Symbol sym;
			if(type == Symbol.CONST)					//  常量，则value表示常量的值，调用常量符号的构造方法
				sym = new Symbol(value, name);
			else										//  变量，则value表示变量的地址，调用变量符号的构造方法
				sym = new Symbol(name, offset++, 0);
			
			symtable.put(sym.name, sym);
			return true;
		}
	}
	
	/**
	 * 		从符号表中查找指定名称的符号
	 * @param name
	 * @return
	 */
	public Symbol getSym(String name){
		Symbol sym = (Symbol)symtable.get(name);			
        return sym;
	}
	
	/**
	 * 		返回函数表当前偏移地址
	 * @return
	 */
	public int getOffset(){
		return offset;
	}
	
	
}
